<template>
  <div v-loading="loading" v-if="!loading">
    <el-table :data="tableData" @header-contextmenu="headerClick" @selection-change="selectionChangeFn" @sort-change="sortChangeFn" :show-summary="tableOpt.summary" :summary-method="summaryMethods" :row-key="tableOpt.rowKey ? tableOpt.rowKey : 'id'" :lazy="tableOpt.lazy" :tree-props="tableOpt.treeProps" @expand-change="emitExpandChange" @cell-click="emitCellClick">
      <el-table-column type="expand" v-if="tableOpt.expand">
        <template #default="form">
          <slot name="expandColumne" :form="form"></slot>
        </template>
      </el-table-column>
      <el-table-column v-if="tableOpt.selection" type="selection" width="55" />
      <template v-for="(column, index) in tableOpt.columns" :key="'C' + index">
        <Column :column="column">
          <template #otherColumn="{ row, column, index }">
            <slot name="otherColumn" :row="row" :column="column" :index="index"></slot>
          </template>
        </Column>
      </template>
      <slot name="otherColumned"></slot>
      <el-table-column label="操作" :width="tableOpt.btnWidth || 250" align="center" v-if="!tableOpt.noBtn">
        <template #default="scope">
          <div class="buttonColumn">
            <slot name="otherBtn" :row="scope.row" :index="scope.$index"></slot>
            <el-button v-if="tableOpt.release?.url" :type="getReleaseItemFn(scope.row)!.btnType" @click="releaseFn(scope.row)"> {{ getReleaseItemFn(scope.row)!.showMsg }} </el-button>
            <el-button type="primary" v-if="!tableOpt.hideEdit" @click="editRowFn(scope.row)">编辑</el-button>
            <el-popconfirm @confirm="deleteFn(scope.row)" title="确认删除吗?">
              <template #reference>
                <el-button type="danger" v-if="tableOpt.delete && (!tableOpt.delete.isShow || tableOpt.delete?.isShow(scope.row))">{{ tableOpt.delete?.deleteTxt || "删除" }}</el-button>
                <div v-else></div>
              </template>
            </el-popconfirm>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <div class="pagination" v-if="!tableOpt.noPage">
      <slot name="simplePage" v-if="tableOpt.simplePage"></slot>
      <el-pagination v-else v-model:currentPage="currentPage" :page-sizes="tableOpt.pageSizes || [5, 10, 30, 50, 100]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="sizeChangeFn" @current-change="currentChangeFn"> </el-pagination>
    </div>
  </div>
</template>

<script lang="ts" setup>
import type { ITableP } from "../index";
import Column from "./compt/column.vue";
import { type NavigationFailure } from "vue-router";

const props = defineProps<ITableP>();
const emit = defineEmits(["emitSelectionChange", "emitExpandChange", "emitCellClick", "emitToOpen", "emitEditHandle", "emitBeforeGetList", "emitAfterGetData", "emitDeleteAfter", "emitHeaderClick"]);
const router = useRouter();
const loading = ref(true);
const tableData = ref([]);
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
const pages = ref(0);
const multipleSelection = ref<any[]>([]);
const moreParams = ref(null);
let searchParams = ["size"];
const selectionChangeFn = (val: any[]) => {
  let arr: any[] = [];
  val.map((item) => {
    props.tableOpt.selectionId ? arr.push(item) : arr.push(item.id);
  });
  multipleSelection.value = arr;
  emit("emitSelectionChange", { arr });
};
const sizeChangeFn = (value: number) => {
  pageSize.value = value;
  emitGetListFn(moreParams.value);
};
const currentChangeFn = (value: number) => {
  currentPage.value = value;
  emitGetListFn(moreParams.value);
};
const headerClick = (column: { property: string }) => {
  emit("emitHeaderClick", { column: column.property });
};
const sortChangeFn = ({ prop, order }: { prop: string; order: "descending" | "ascending" }) => {
  // 处理后续用到补充
  emitGetListFn(moreParams.value);
};
function emitCellClick(...[row, column, cell, event]: any[]) {
  emit("emitCellClick", { row, column, cell, event });
}
function emitExpandChange(...[row, expanded]: any[]) {
  emit("emitExpandChange", { row, expanded });
}
const summaryMethods = ({ columns, data }: { columns: { property: string }[]; data: any }): string[] => {
  const sums: string[] = [];
  columns.forEach((column, index) => {
    if (index === 0) {
      return (sums[index] = "合计");
    }
    const values = data.map((item: any) => Number(item[column.property]));
    let setting = props.tableOpt.columns.find((item) => {
      return column.property == item.prop;
    });
    if (!values.every((value: number[]) => Number.isNaN(value)) && !setting?.noSum) {
      sums[index] = `${values.reduce((prev: number, curr: number) => {
        const value = Number(curr);
        if (!Number.isNaN(value)) {
          return parseFloat((prev + curr).toFixed(2));
        } else {
          return prev;
        }
      }, 0)}`;
    } else {
      sums[index] = "N/A";
    }
  });
  return sums;
};

const editRowFn = (row: any): Promise<void | NavigationFailure | undefined> | undefined => {
  let rowCopy = ref(row);
  emit("emitEditHandle", { rowCopy });
  if (props.tableOpt.jumpAdd) {
    return router.push(`${props.tableOpt.detailPage}/${rowCopy.value.id}`);
  }
  nextTick(() => {
    emit("emitToOpen", { row: rowCopy.value });
  });
};
const emitGetListFn = async (e: any, dom?: boolean) => {
  let obj = {};
  if (props.tableOpt.list?.params) obj = Object.assign(obj, props.tableOpt.list?.params);
  if (dom) currentPage.value = 1;
  if (!props.tableOpt.noPage) obj = Object.assign(obj, { size: pageSize.value, page: currentPage.value });
  if (e) {
    moreParams.value = e;
    obj = Object.assign(obj, e);
  }
  let objed: { [key: string]: any } = {};
  for (let item in obj) {
    let value = obj[item as keyof typeof obj];
    let isClear = props.tableOpt.notClear && props.tableOpt.notClear[item] && props.tableOpt.notClear[item].includes(value);
    if (value || item == "size" || item == "page" || isClear) objed[item] = value;
  }
  if (props.tableOpt.beforeGetList) emit("emitBeforeGetList", { obj });
  let request = props.tableOpt.otherRequest || hfoRequest;
  let res = await request.get({ url: props.tableOpt.list?.url, params: objed });
  if (res) {
    if (!props.tableOpt.noPage) {
      total.value = res.data.totalElements;
      pages.value = res.data.totalElements / pageSize.value;
    }
    if (props.tableOpt.emitAfterGetData) {
      emit("emitAfterGetData", { res });
    } else {
      tableData.value = res.data.list;
    }
  }
  loading.value = false;
};
function getReleaseItemFn(row: any) {
  let stateKey = row[props.tableOpt.release!.props];
  return props.tableOpt.release!.releaseItem.find((item) => {
    return item.state == stateKey;
  });
}
const releaseFn = async (row: any) => {
  let res = await hfoRequest.put({ url: props.tableOpt.release?.url, data: row });
  if (res) {
    ElMessage.success(getReleaseItemFn(row)!.changeMsg);
    emitGetListFn(moreParams.value);
  }
};
function initiazaReleaseFn() {
  if (props.tableOpt.release) {
    let obj = props.tableOpt.release;
    if (!obj.releaseItem)
      obj.releaseItem = [
        { state: true, changeMsg: "下架成功", showMsg: "上架", btnType: "primary" },
        { state: false, changeMsg: "上架成功", showMsg: "下架", btnType: "danger" }
      ];
    if (!props.tableOpt.release.props) props.tableOpt.release!.props = "state";
  }
}
const deleteFn = async (row: any) => {
  if (!props.tableOpt.delete) return;
  let request = props.tableOpt.otherRequest || hfoRequest;
  let res = await request.delete({ url: `${props.tableOpt.delete?.url}/${row.id}` });
  if (res.statusCode == 200) {
    if (props.tableOpt.delete?.emitDeleteAfter) return emit("emitDeleteAfter");
    ElMessage.success("删除成功");
    emitGetListFn(moreParams.value);
  }
};
const route = useRoute();
onMounted(() => {
  if (route.name == "coderCreate") loading.value = false;
  if (props.tableOpt.pageSize) pageSize.value = props.tableOpt.pageSize;
  initiazaReleaseFn();
  if (!props.tableOpt.noData && props.tableOpt.list?.url) {
    emitGetListFn(null);
  }
  if (props.tableOpt.notClear) {
    for (const key in props.tableOpt.notClear) {
      searchParams.push(key);
    }
  }
});
let tableEx: ITableEx = { emitGetListFn, tableData };
defineExpose({
  ...tableEx
});
</script>

<style lang="scss" scoped>
.pagination {
  margin: 20px 0;
  text-align: right;
}
</style>
